/** 
 * This file is a part of qloudgen-sec. 
 * You can redistribute qloudgen-sec and/or modify it under the terms of the Lesser GNU General Public License version 3. 
 * qloudgen-sec is distributed WITHOUT ANY WARRANTY. 
 *
 * See the Lesser GNU General Public License for more details at http://www.gnu.org/licenses/. 
 **/
package org.qloudgen.sec.util;

import org.apache.commons.jxpath.JXPathContext;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * <p>Title: XPath tools</p>
 * <p>Description: Implementation common xpath handle based apache commons-jxpath.</p>
 * <p>Copyright: qloudgen/sec 2012</p>
 * @author <a href="mailto:hyq.dd.sun@gmail.com">glue.3M</a>
 */
public final class XPathUtil {
	/**
	 * Log output.
	 */
	private final static Logger logger = LoggerFactory.getLogger( XPathUtil.class );
	
	/**
	 *
	 *
	 * @param context
	 * @param result
	 * @param xpath
	 */
	public static Object handle(String context , Object result , String xpath) {
		//
		return handle( context , true , result , xpath );
	}
	
	/**
	 * The xpath expression must start with "result" when using none-bean model.
	 *
	 * @param context
	 * @param isBean
	 * @param result
	 * @param xpath
	 */
	public static Object handle(String context , boolean isBean , Object result , String xpath) {
		//
		if ( isBean ) {
			return getInstance( context , result ).getValue( xpath );
		}
		else {
			return getInstance( context , new XPathBean<Object>( result ) ).getValue( xpath );
		}
	}

	/**
	 * For now we only support JXPath implementation.
	 *
	 * @param context
	 * @param result
	 * @return JXPathContext
	 */
	private static JXPathContext getInstance(String context , Object result) {
		//
		try {
			// Create context.
			JXPathContext jxPathContext = ( JXPathContext )( ClassUtil.forName( context ).getMethod( "newContext" , new Class[]{ Object.class } ).invoke( null , new Object[]{ result } ) );
			/**
			 * If the context is in the lenient mode, then getValue() returns null for inexistent paths.
			 * By default, lenient = false
			 */
			jxPathContext.setLenient( true );
			//
			return jxPathContext;
		}
		catch (Throwable t) {
			logger.error( "Unknown xpath implementation...\n{}" , ExceptionUtil.get( t ) );
		}
		//
		return null;
	}
	
	/**
	 * Internal bean wrapper implementation.
	 */
	public static class XPathBean<E> {
		/**
		 *
		 */
		private E result = null;
		
		/**
		 *
		 *
		 * @param E result
		 */
		public XPathBean(E result) {
			this.result = result;
		}
		
		/**
		 *
		 *
		 * @param E result
		 */
		public void setResult(E result) {
			this.result = result;
		}
		
		/**
		 *
		 *
		 * @return E
		 */
		public E getResult() {
			return result;
		}
	}
}